package com.freexiaoyu.freevideoplay;


import android.media.MediaCodec;
import android.media.MediaFormat;
import android.os.Bundle;
import android.util.Log;
import android.view.Surface;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.nio.ByteBuffer;

public class VideoActivity2 extends AppCompatActivity implements SurfaceHolder.Callback {

    private static final String TAG = "VideoStreamServer";
    private DatagramSocket udpSocket;
    private Thread udpReceiverThread = null;
    private MediaCodec mediaCodec;
    private SurfaceHolder surfaceHolder;
    private byte[] videoBuffer = new byte[10 * 1024 * 1024]; // Large buffer to hold video frames
    private int bufferPos = 0;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_video_play);

        SurfaceView surfaceView = findViewById(R.id.surfaceView);
        surfaceHolder = surfaceView.getHolder();
        surfaceHolder.addCallback(this);

        startUdpReceiver();
    }

    private void startUdpReceiver() {
        udpReceiverThread = new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    udpSocket = new DatagramSocket(22001);
                    Log.d(TAG, "UDP Receiver started on port 22001");

                    byte[] receiveBuffer = new byte[65507]; // Maximum UDP packet size
                    while (true) {
                        DatagramPacket packet = new DatagramPacket(receiveBuffer, receiveBuffer.length);
                        udpSocket.receive(packet);
                        Log.d(TAG, "Received packet from: " + packet.getAddress().getHostAddress());

                        byte[] receivedData = new byte[packet.getLength()];
                        System.arraycopy(packet.getData(), packet.getOffset(), receivedData, 0, packet.getLength());

                        processReceivedData(receivedData);
                    }
                } catch (IOException e) {
                    Log.e(TAG, "Error in UDP receiver", e);
                }
            }
        });

        udpReceiverThread.start();
    }

    private void processReceivedData(byte[] data) {
        if (data.length < 2) {
            Log.w(TAG, "Received data too short to contain frame length");
            return;
        }

        int frameLength = ((data[0] & 0xFF) << 8) | (data[1] & 0xFF);
        int dataPos = 2; // Start after the frame length bytes

        while (bufferPos + (data.length - dataPos) > videoBuffer.length) {
            Log.w(TAG, "Video buffer full, discarding old data");
            bufferPos = 0; // Reset buffer position if it's full
        }

        // Copy received data into video buffer
        System.arraycopy(data, dataPos, videoBuffer, bufferPos, data.length - dataPos);
        bufferPos += data.length - dataPos;

        // Check if we have a complete frame
        while (bufferPos >= 2) {
            frameLength = ((videoBuffer[0] & 0xFF) << 8) | (videoBuffer[1] & 0xFF);
            if (bufferPos >= frameLength + 2) {
                // Extract the frame
                byte[] frameData = new byte[frameLength];
                System.arraycopy(videoBuffer, 2, frameData, 0, frameLength);

                // Decode the video frame
                decodeVideoFrame(frameData);

                // Shift remaining data in the buffer
                System.arraycopy(videoBuffer, frameLength + 2, videoBuffer, 0, bufferPos - (frameLength + 2));
                bufferPos -= frameLength + 2;
            } else {
                break;
            }
        }
    }

    @Override
    public void surfaceCreated(@NonNull SurfaceHolder holder) {
        configureDecoder(holder.getSurface());
    }

    @Override
    public void surfaceChanged(@NonNull SurfaceHolder holder, int format, int width, int height) {}

    @Override
    public void surfaceDestroyed(@NonNull SurfaceHolder holder) {
        releaseDecoder();
    }

    private void configureDecoder(Surface surface) {
        try {
            mediaCodec = MediaCodec.createDecoderByType("video/avc");
            MediaFormat format = MediaFormat.createVideoFormat("video/avc", 1920, 1080); // Adjust resolution as needed
            mediaCodec.configure(format, surface, null, 0);
            mediaCodec.start();
        } catch (IOException e) {
            Log.e(TAG, "Failed to create decoder", e);
        }
    }

    private void releaseDecoder() {
        if (mediaCodec != null) {
            mediaCodec.stop();
            mediaCodec.release();
            mediaCodec = null;
        }
    }

    private void decodeVideoFrame(byte[] data) {
        ByteBuffer[] inputBuffers = mediaCodec.getInputBuffers();
        ByteBuffer[] outputBuffers = mediaCodec.getOutputBuffers();

        int inputBufferIndex = mediaCodec.dequeueInputBuffer(-1);
        if (inputBufferIndex >= 0) {
            ByteBuffer inputBuffer = inputBuffers[inputBufferIndex];
            inputBuffer.clear();
            inputBuffer.put(data);
            mediaCodec.queueInputBuffer(inputBufferIndex, 0, data.length, 0, 0);
        }

        MediaCodec.BufferInfo bufferInfo = new MediaCodec.BufferInfo();
        int outputBufferIndex = mediaCodec.dequeueOutputBuffer(bufferInfo, 0);
        while (outputBufferIndex >= 0) {
            mediaCodec.releaseOutputBuffer(outputBufferIndex, true);
            outputBufferIndex = mediaCodec.dequeueOutputBuffer(bufferInfo, 0);
        }
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        if (udpSocket != null && !udpSocket.isClosed()) {
            udpSocket.close();
        }
        releaseDecoder();
    }
}



